package com.xpec.c4.codec.h2o;

import java.io.IOException;

public class H2oOutputStream {
	private H2oOutputStream() {
	}

	protected static void writeBoolean(H2oBuffer buffer, boolean value) throws IOException {
		buffer.put((byte) (value ? 1 : 0));
	}
	
	protected static void writeByte(H2oBuffer buffer, byte value) throws IOException {
		buffer.put(value);
	}

	protected static void writeNumber(H2oBuffer buffer, long value) throws IOException {
		writeRawVarint(buffer, value);
	}

	protected static void writeFloat(H2oBuffer buffer, float value) throws IOException {
		buffer.putFloat(value);
	}

	protected static void writeDouble(H2oBuffer buffer, double value) throws IOException {
		buffer.putDouble(value);
	}

	protected static void writeString(H2oBuffer buffer, String value) throws IOException {
		writeBytes(buffer, value.getBytes(CodedInfo.CHARSET_NAME));
	}

	protected static void writeBytes(H2oBuffer buffer, byte[] value) throws IOException {
		// size
		writeRawVarint(buffer, value.length);
		// value
		buffer.put(value);
	}

	protected static void writeTag(H2oBuffer buffer, int field, int wireType) throws IOException {
		writeRawVarint(buffer, WireFormat.makeTag(field, wireType));
	}

	protected static void writeRawVarint(H2oBuffer buffer, long value) throws IOException {
		while (true) {
			if ((value & ~0x7F) == 0) {
				buffer.put((byte) value);
				break;
			} else {
				buffer.put((byte) ((value & 0x7F) | 0x80));
				value >>>= 7;
			}
		}
	}

	/**
	 * 将数值《移动》到指定位置
	 * 
	 * @param buffer
	 * @param index
	 * @param value
	 */
	protected static void writeRawVarint(H2oBuffer buffer, int index, long value) {
		int p = 0;
		byte[] bytes = new byte[8];
		while (true) {
			if ((value & ~0x7F) == 0) {
				bytes[p++] = (byte) value;
				break;
			} else {
				bytes[p++] = (byte) ((value & 0x7F) | 0x80);
				value >>>= 7;
			}
		}

		buffer.insert(index, bytes, p);
//		int pos = buffer.position();
//		buffer.position(index);
//		byte[] cpy = new byte[pos - index];
//		buffer.get(cpy);
//		buffer.position(index);
//		buffer.put(bytes, 0, p);
//		buffer.put(cpy);
	}

	protected static int computeRawVarintSize(long value) {
		if ((value & (0xffffffffffffffffL << 7)) == 0)
			return 1;
		if ((value & (0xffffffffffffffffL << 14)) == 0)
			return 2;
		if ((value & (0xffffffffffffffffL << 21)) == 0)
			return 3;
		if ((value & (0xffffffffffffffffL << 28)) == 0)
			return 4;
		if ((value & (0xffffffffffffffffL << 35)) == 0)
			return 5;
		if ((value & (0xffffffffffffffffL << 42)) == 0)
			return 6;
		if ((value & (0xffffffffffffffffL << 49)) == 0)
			return 7;
		if ((value & (0xffffffffffffffffL << 56)) == 0)
			return 8;
		if ((value & (0xffffffffffffffffL << 63)) == 0)
			return 9;
		return 10;
	}
}
